# 11. 测试代码
# vscode运行unittest框架： https://blog.csdn.net/CloserSide/article/details/109175775
import unittest
from bean.name_function import get_formatted_name


class NameTestCase(unittest.TestCase):
    """测试name_function.py"""
    def test_first_last_name(self):
        """能够正确处理Jolin Kojo这样的姓名吗？"""
        formatted_name = get_formatted_name("Jolin", "Kojo")
        self.assertEqual(formatted_name, "Jolin Kojo")


if __name__ == '__main__':
    unittest.main()

# 更多的测试选项 https://docs.python.org/zh-cn/3/library/unittest.html
# 1. unittest 提供一个基类： TestCase ，用于新建测试用例。
#   1） 测试类要继承unittest.TestCase，测试方法的命名要以test开头。

#   2）unittest 模块可以通过命令行运行模块、类和独立测试方法的测试:
#       python -m unittest test_module1 test_module2
#       python -m unittest test_module.TestClass
#       python -m unittest test_module.TestClass.test_method
#   你可以传入模块名、类或方法名或他们的任意组合。

#   3）同样的，测试模块可以通过文件路径指定:
#       python -m unittest tests/test_something.py
#   这样就可以使用 shell 的文件名补全指定测试模块。所指定的文件仍需要可以被作为模块导入。
#   路径通过去除 '.py' 、把分隔符转换为 '.' 转换为模块名。
#   若你需要执行不能被作为模块导入的测试文件，你需要直接执行该测试文件。

#   4）在运行测试时，你可以通过添加 -v 参数获取更详细（更多的冗余）的信息。
#       python -m unittest -v test_module

#   5）当运行时不包含参数，开始 探索性测试
#       python -m unittest

#   6）用于获取命令行选项列表：
#       python -m unittest -h

#   7）在 3.2 版更改: 在早期版本中，只支持运行独立的测试方法，而不支持模块和类。


class TestStringMethods(unittest.TestCase):
    def setUp(self):
        print('\nsetUp - %s' % self._testMethodName)

    def tearDown(self):
        print("tearDown - %s" % self._testMethodName)

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)


# 2. 测试方法
#   1）断言：
#       调用 assertEqual() 来检查预期的输出；
#       调用 assertTrue() 或 assertFalse() 来验证一个条件；
#       调用 assertRaises() 来验证抛出了一个特定的异常。
#   2）开始前和完成后
#       setUp(): 每个测试都会单独调用一次。
#       tearDown(): 测试方法运行后进行清理工作。
#    3) 其他：
#       1、若setUp()方法引发异常，测试终止。
#       2、多个测试运行的顺序由内置字符串排序方法对测试名进行排序的结果决定。
#
#    4) 使用unittest.TestSuite() 可以自定义测试顺序
#       运行测试: python  .\_11_testing_code.py


def suite():
    suite = unittest.TestSuite()
    suite.addTest(TestStringMethods('test_upper'))
    suite.addTest(TestStringMethods('test_isupper'))
    return suite


if __name__ == '__main__':
    runner = unittest.TextTestRunner()
    runner.run(suite())

# 3. 探索性测试
# 3.2 新版功能.
# Unittest支持简单的测试搜索。若需要使用探索性测试，
# 所有的测试文件必须是 modules 或 packages （包括 namespace packages )
# 并可从项目根目录导入（即它们的文件名必须是有效的 identifiers ）。

# 探索性测试在 TestLoader.discover() 中实现，但也可以通过命令行使用。
# 它在命令行中的基本用法如下：
#    cd project_directory
#    python -m unittest discover

# 注解：方便起见， python -m unittest 与 python -m unittest discover 等价。
# 如果你需要向探索性测试传入参数，必须显式地使用 discover 子命令。

# discover 有以下选项：
# -v, --verbose
#   更详细地输出结果。
# -s, --start-directory directory
#   开始进行搜索的目录(默认值为当前目录 . )。
# -p, --pattern pattern
#   用于匹配测试文件的模式（默认为 test*.py ）。
# -t, --top-level-directory directory
#   指定项目的最上层目录（通常为开始时所在目录）。

# -s ，-p 和 -t 选项可以按顺序作为位置参数传入。以下两条命令是等价的：
# python -m unittest discover -s project_directory -p "*_test.py"
# python -m unittest discover project_directory "*_test.py"

# 正如可以传入路径那样，传入一个包名作为起始目录也是可行的，如 myproject.subpackage.test 。
# 你提供的包名会被导入，它在文件系统中的位置会被作为起始目录。

# 警告 探索性测试通过导入测试对测试进行加载。
# 在找到所有你指定的开始目录下的所有测试文件后，它把路径转换为包名并进行导入。
# 如 foo/bar/baz.py 会被导入为 foo.bar.baz 。
# 如果你有一个全局安装的包，并尝试对这个包的副本进行探索性测试，可能会从错误的地方开始导入。
# 如果出现这种情况，测试会输出警告并退出。

# 如果你使用包名而不是路径作为开始目录，搜索时会假定它导入的是你想要的目录，所以你不会收到警告。

# 测试模块和包可以通过 load_tests protocol 自定义测试的加载和搜索。

# 在 3.4 版更改: 测试发现支持初始目录下的 命名空间包。
# 注意你也需要指定顶层目录
# （例如：python -m unittest discover -s root/namespace -t root）。
